import json
import os
import time

import hypercorn.asyncio
import jwt
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from flask import Flask, request, jsonify
from flask_cors import CORS
from hypercorn.config import Config

from my_models import client, config, Datas, base_path

app = Flask(__name__)
CORS(app)

SECRET_KEY = "cqu_secret_key"
TOKEN_EXPIRATION_TIME = config["token_expiration_time"]

# 读取私钥
f = open(os.path.join(base_path, "private_key.pem"), "rb")
private_key = serialization.load_pem_private_key(f.read(), password=None)
f.close()


async def verify_token_post(request):
    try:
        authorization = request.headers.get("Authorization")
        if not authorization:
            return {"error": "Authorization header missing"}
        token = authorization.split(" ")[1]
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        # 接收并解析客户端发送的加密数据（十六进制格式）
        encrypted_data_hex = request.json["data"]
        encrypted_data = bytes.fromhex(encrypted_data_hex)  # 将十六进制转换为字节流格式
        # 使用私钥解密数据
        decrypted_data = private_key.decrypt(
            encrypted_data,
            padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
        ).decode()
        # 将解密后的 JSON 字符串转换为字典
        original_data = json.loads(decrypted_data)
        original_data["sub"] = payload["sub"]
        return original_data
    except jwt.ExpiredSignatureError:
        return {"error": "Token expired"}
    except jwt.InvalidTokenError:
        return {"error": "Invalid token"}
    except:
        return {"error": "Token unknown error"}


@app.route("/data", methods=["POST"])
async def add_data():
    # 验证令牌并解密数据
    original_data = await verify_token_post(request)
    if "error" in original_data:
        return jsonify(original_data), 401
    # 解析数据
    try:
        data = Datas(
            time=original_data["time"],
            h=original_data["h"],
            m=original_data["m"],
            sbp=original_data["sbp"],
            dbp=original_data["dbp"],
            device_id=original_data["id"]
        )
    except Exception as e:
        return jsonify({"error": "Bad request" + str(e)}), 400
    # 将数据插入数据库
    try:
        client.blood_pressure.datas.insert_one(data.model_dump())
        return jsonify({"message": "Access granted", "user": original_data["sub"]}), 200
    except:
        return jsonify({"error": "Database error"}), 500


@app.route("/get_access_token", methods=["POST"])
async def get_access_token():
    ticket = None
    try:
        ticket = request.json.get("ticket")
    finally:
        if not ticket:
            return jsonify({"error": "Invalid request"}), 400
    # 从数据库中获取密钥
    tickets = client.blood_pressure.tickets.find_one({"ticket": ticket})
    if tickets:
        username = tickets["device_id"]
        payload = {"sub": username, "iat": time.time(), "exp": time.time() + TOKEN_EXPIRATION_TIME}
        token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
        return jsonify({"access_token": token}), 200
    else:
        return jsonify({"error": "Invalid ticket"}), 401


if __name__ == "__main__":
    config = Config()
    config.bind = ["0.0.0.0:5000"]
    config.debug = True  # 开启调试模式
    hypercorn.asyncio.serve(app, config)
